//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <elasys_server.h>
#include "CBasicDirectory.h"
#include "CDirEnumerator.h"
#include "Winhack.h"
#include <stdlib.h>
#include "aura.h"

#define FIXME Aura_printf("[FixMe]<%s> Not Implemented.\n", __FUNCTION__);

#define LockDirList do {AuraCriticalSection_Enter(m_hDirListLock);} while (0);
#define UnlockDirList do {AuraCriticalSection_Leave(m_hDirListLock);} while (0);

#define LockFileList do {AuraCriticalSection_Enter(m_hFileListLock);} while (0);
#define UnlockFileList do {AuraCriticalSection_Leave(m_hFileListLock);} while (0);

#define LockFile do {AuraCriticalSection_Enter(m_hFileLock);} while (0);
#define UnlockFile do {AuraCriticalSection_Leave(m_hFileLock);} while (0);

CBasicDirectory::CBasicDirectory(IBasicDirectory *pParent)
{
    m_pDirName = NULL;
    m_CreateTime = 0;
    m_LastAccessTime = 0;
    m_LastModifyTime = 0;

    m_pDirName = NULL;
    m_hFileLock = NULL;
    m_hFileListLock = NULL;
    m_hDirListLock = NULL;
    m_hParentDirListLock = NULL;

    m_DirObjectList.Initialize();
    m_FileObjectList.Initialize();

    m_pParentDir = pParent;
    m_IsRootDir = (NULL == m_pParentDir ? TRUE : FALSE);
    if (!m_IsRootDir) {
        m_hParentDirListLock = (static_cast<CBasicDirectory *>(pParent))->GetDirObjectListLock();
    }
}

ECode CBasicDirectory::Initialize(WString dirName)
{
    ECode ec = NOERROR;
    DWORD fileAttribute = 0;

    m_pDirName = (wchar_t *)(Aura_malloc(sizeof(wchar_t) * (wcslen(dirName) + 1)));
    if (NULL == m_pDirName) {
        ec = E_OUT_OF_MEMORY;
        goto E_FAIL_EXIT;
    }
    //if (!dirName.StartWith(L"C:\\Temp", StringCase_Insensitive))
    wcscpy(m_pDirName, dirName);
    //else
    //    wcscpy(m_pDirName, (const wchar_t *)(dirName) + 2);

    ec = AuraCriticalSection_Create(&m_hDirListLock);
    if (AURA_NOERROR != ec) {
        goto E_FAIL_EXIT;
    }
    ec = AuraCriticalSection_Create(&m_hFileListLock);
    if (AURA_NOERROR != ec) {
        goto E_FAIL_EXIT;
    }
    ec = AuraCriticalSection_Create(&m_hFileLock);
    if (AURA_NOERROR != ec) {
        goto E_FAIL_EXIT;
    }

    fileAttribute = GetFileAttributesW(m_pDirName);
    if (INVALID_FILE_ATTRIBUTES == fileAttribute) {
        ec = E_INVALID_OPERATION;
        goto E_FAIL_EXIT;
    }

    if (fileAttribute & FILE_ATTRIBUTE_READONLY)
        m_DirAccessMode = FileAccessMode_Read;
    else 
        m_DirAccessMode = FileAccessMode_ReadWrite;

    m_DirShareMode = FileShareMode_Write;

    return NOERROR;

E_FAIL_EXIT:
    if (NULL != m_pDirName) {
        Aura_free(m_pDirName);
        m_pDirName = NULL;
    }
    if (NULL != m_hDirListLock) {
        AuraCriticalSection_Destroy(m_hDirListLock);
        m_hDirListLock = NULL;
    }
    if (NULL != m_hFileListLock) {
        AuraCriticalSection_Destroy(m_hFileListLock);
        m_hFileListLock = NULL;
    }
    if (NULL != m_hFileLock) {
        AuraCriticalSection_Destroy(m_hFileLock);
        m_hFileLock = NULL;
    }

    return ec;
    
}

CBasicDirectory::~CBasicDirectory()
{
    assert(m_DirObjectList.IsEmpty());
    assert(m_FileObjectList.IsEmpty());

    if (NULL != m_pDirName)
        Aura_free(m_pDirName);

    if (!m_IsRootDir)
        this->Detach();

    if (NULL != m_hDirListLock)
        AuraCriticalSection_Destroy(m_hDirListLock);
    if (NULL != m_hFileListLock)
        AuraCriticalSection_Destroy(m_hFileListLock);
    if (NULL != m_hFileLock)
        AuraCriticalSection_Destroy(m_hFileLock);

}

UInt32 CBasicDirectory::AddRef()
{
    UInt32 cRef = m_cRef.Increment();
    return cRef;
}

UInt32 CBasicDirectory::Release()
{
    UInt32 cRef = 0;
    Aura_Handle hParentDirListLock = NULL;
    CBasicDirectory *pParentDir = NULL;

    if (!m_IsRootDir) {
        hParentDirListLock = m_hParentDirListLock;
        pParentDir = static_cast<CBasicDirectory *>(m_pParentDir);

        AuraCriticalSection_Enter(hParentDirListLock);
        cRef = m_cRef.Decrement();
        if (0 == cRef) {
            delete this;
            AuraCriticalSection_Leave(hParentDirListLock);
            pParentDir->Release();
            return cRef;
        }
        AuraCriticalSection_Leave(hParentDirListLock);
    } else {
        cRef = m_cRef.Decrement();
        if (0 == cRef) {
            delete this;
        }
    }
    return cRef;
}

PInterface CBasicDirectory::Probe(REIID riid)
{
    if (EIID_IInterface == riid) {
        return (IInterface *)(IBasicDirectory *)this;
    }
    else if (EIID_IBasicFile == riid) {
        return (IBasicFile *)(IBasicDirectory *)this;
    }
    else if (EIID_IBasicDirectory == riid) {
        return (IBasicDirectory *)this;
    }
    else if (EIID_IFileMonitor == riid) {
        return (IFileMonitor *)this;
    }
    else if (EIID_CLASS_INFO == riid) {
        return (IInterface *)&ECLSID_CKtfsDirectory;
    }
    else if (EIID_INTERFACE_INFO == riid) {
        return (IInterface *)&EIID_IBasicDirectory;
    }

    return NULL;
}

ECode CBasicDirectory::MakeFullName(
    WString name, wchar_t *fullname)
{
    assert(NULL != m_pDirName);
    wchar_t *wcsName = fullname;
    wcscat(wcsName, m_pDirName);
    if (!m_IsRootDir) {
        wcscat(wcsName, L"\\");
    }
    wcscat(wcsName, name);
    return NOERROR;
}

ECode CBasicDirectory::Aggregate(
    AggregateType type, PInterface pObj)
{
    FIXME;
    return E_NOT_IMPLEMENTED;
}

ECode CBasicDirectory::GetDomain(
    IInterface **ppObj)
{
    FIXME;
    return E_NOT_IMPLEMENTED;
}

ECode CBasicDirectory::Sync()
{
    return NOERROR;
}

ECode CBasicDirectory::GetType(
    /* [out] */ FileType * pType)
{
    if (NULL == pType) {
        return E_INVALID_ARGUMENT;
    }

    *pType = FileType_Directory;
    return NOERROR;
}

ECode CBasicDirectory::GetAccessTime(
    /* [out] */ Int32 * pTime)
{
    ECode ec = NOERROR;

    if (NULL == pTime) {
        return E_INVALID_ARGUMENT;
    }

    if (0 == m_LastAccessTime) {
        ec = GetDirTime();
        if (NOERROR != ec)
            return ec;
    }

    *pTime = m_LastAccessTime;
    return NOERROR;
}

ECode CBasicDirectory::SetAccessTime(
    /* [in] */ Int32 time)
{
    FIXME;
    return E_NOT_IMPLEMENTED;
}

ECode CBasicDirectory::GetModificationTime(
    /* [out] */ Int32 * pTime)
{
    ECode ec = NOERROR;

    if (NULL == pTime) {
        return E_INVALID_ARGUMENT;
    }
    if (0 == m_LastModifyTime) {
        ec = GetDirTime();
        if (NOERROR != ec)
            return ec;
    }
    *pTime = m_LastModifyTime;
    return NOERROR;
}

ECode CBasicDirectory::SetModificationTime(
    /* [in] */ Int32 time)
{
    FIXME;
    return E_NOT_IMPLEMENTED;
}

ECode CBasicDirectory::GetCreateTime(
    /* [out] */ Int32 * pTime)
{
    ECode ec = NOERROR;

    if (NULL == pTime) {
        return E_INVALID_ARGUMENT;
    }
    if (0 == m_CreateTime) {
        ec = GetDirTime();
        if (NOERROR != ec)
            return ec;
    }
    *pTime = m_CreateTime;
    return NOERROR;
}

ECode CBasicDirectory::CheckAccessMode(
    /* [in] */ FileAccessMode mode)
{
    FIXME;
    return E_NOT_IMPLEMENTED;
}

ECode CBasicDirectory::GetAccessMode(
    /* [out] */ FileAccessMode * pMode)
{
    if (NULL == pMode) {
        return E_INVALID_ARGUMENT;
    }

    *pMode = m_DirAccessMode;
    if (m_DirAccessMode == FileAccessMode_Write) {
        *pMode = FileAccessMode_ReadWrite;
    }

    return NOERROR;
}

ECode CBasicDirectory::SetAccessMode(
    /* [in] */ FileAccessMode mode)
{
    DWORD attr = 0;

    if (mode != FileAccessMode_Read
       && mode != FileAccessMode_Write
       && mode != FileAccessMode_ReadWrite) {
        return E_INVALID_ARGUMENT;
    }

    attr = GetFileAttributesW(m_pDirName);
    if (mode == FileAccessMode_Read) {
        attr |= FILE_ATTRIBUTE_READONLY;
    }
    else {
        attr &= ~FILE_ATTRIBUTE_READONLY;
    }
    SetFileAttributesW(m_pDirName, attr);
    m_DirAccessMode = mode;
    return NOERROR;
}

ECode CBasicDirectory::GetShareMode(
    /* [out] */ FileShareMode * pMode)
{
    FIXME;
    return E_NOT_IMPLEMENTED;
}

ECode CBasicDirectory::SetShareMode(
    /* [in] */ FileShareMode mode)
{
    FIXME;
    return E_NOT_IMPLEMENTED;
}

ECode CBasicDirectory::Lookup(
    /* [in] */ WString name,
    /* [out] */ IBasicFile ** piBasicFile)
{
    ECode ec = NOERROR;
    Boolean bIsExist = false;
    Boolean bIsDir = false;
    CBasicDirectory *pDir = NULL;
    CBasicFile *pFile = NULL;
    DWORD fileAttribute = 0;
    wchar_t wcsName[_MAX_PATH] = {0,};
    FileAccessMode accessMode = FileAccessMode_ReadWrite;
    FileShareMode shareMode = FileShareMode_Write;

    if (name.IsNullOrEmpty()
        ||wcspbrk((const wchar_t *)name, wszIllegal) != NULL
        || piBasicFile == NULL
        || name.GetLength() > (_MAX_PATH - 5) //MAX_PATH is 260
        || (name.GetLength() + wcslen(m_pDirName)) >= _MAX_PATH) {
        return E_INVALID_ARGUMENT;
    }

    MakeFullName(name, wcsName);

    LockFile;
    CheckFileType(wcsName, &bIsExist, &bIsDir);
    UnlockFile;

    if (!bIsExist)
        return E_FS_NO_SUCH_FILE;
 
    if (bIsDir) {
        LockDirList;
        pDir = LookUpDirObject(wcsName);
        if (NULL == pDir) {
            pDir = new CBasicDirectory(static_cast<IBasicDirectory *>(this));
            if (NULL == pDir) {
                UnlockDirList;
                return E_OUT_OF_MEMORY;
            }

            ec = pDir->Initialize(wcsName);
            if (FAILED(ec)) {
                UnlockDirList;
                goto E_FAIL_EXIT;
            }
            this->AddRef();
            m_DirObjectList.InsertNext(pDir);
        }
        pDir->AddRef();
        UnlockDirList;
        *piBasicFile = (IBasicFile *)pDir;
        return NOERROR;

    } else {//File
        LockFileList;
        pFile = LookUpFileObject(wcsName);
        if (NULL == pFile) {
            pFile = new CBasicFile(static_cast<IBasicDirectory *>(this));
            if (NULL == pFile) {
                UnlockFileList;
                return E_OUT_OF_MEMORY;
            }

            ec = pFile->Initialize(wcsName, shareMode);
            if (NOERROR != ec) {
                UnlockFileList;
                goto E_FAIL_EXIT;
            }
 
            m_FileObjectList.InsertNext(pFile);
            this->AddRef();
        }

        pFile->AddRef();
        UnlockFileList;
        *piBasicFile = (IBasicFile *)pFile;
        return NOERROR;
    }

E_FAIL_EXIT:
    if (NULL != pDir) {
        delete pDir;
    }
    if (NULL != pFile) {
        delete pFile;
    }
    return ec;
}

ECode CBasicDirectory::CreateFile(
    /* [in] */ WString name,
    /* [in] */ FileAccessMode cmode,
    /* [in] */ Boolean bExclusive,
    /* [out] */ IBasicFile ** piBasicFile)
{
    WStringBuf_<_MAX_PATH> ws;
    ECode ec = NOERROR;
    Boolean isExist = false;
    Boolean isDir = false;
    Boolean isWritable = true;
    wchar_t wcsName[_MAX_PATH] = {0,};
    CBasicFile *pFile = NULL;
    FileShareMode shareMode = FileShareMode_Write;
    HANDLE fileHandle = INVALID_HANDLE_VALUE;

    name = name.TrimEnd(ws);
    if (name.IsNullOrEmpty()
        || NULL == piBasicFile || name.GetLength() > (_MAX_PATH - 5)
        || ((name.GetLength() + wcslen(m_pDirName)) >= _MAX_PATH)
        || wcspbrk((const wchar_t *)name, wszIllegal) != NULL
        || !(FileAccessMode_Read == cmode 
           || FileAccessMode_Write == cmode
           || FileAccessMode_ReadWrite == cmode)) {
        return E_INVALID_ARGUMENT;
    }

    MakeFullName(name, wcsName);

    LockFile;
    CheckFileType(wcsName, &isExist, &isDir);
    if (isExist) {
        if (isDir) {
            UnlockFile;
            return E_FS_IS_DIRECTORY;
        } 

        if (bExclusive) {// for file.
            UnlockFile;
            return E_FS_FILE_EXISTS;
        }
    } else {
        Int32 accessMode = GENERIC_READ;
        Int32 shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
        Int32 fileAttribute = FILE_ATTRIBUTE_NORMAL;
        Int32 createMode = CREATE_ALWAYS;

        if (FileAccessMode_Write == cmode || FileAccessMode_ReadWrite == cmode)
            accessMode |= GENERIC_WRITE;

        fileHandle = CreateFileW(wcsName, accessMode, 
                              shareMode, NULL, createMode, fileAttribute, NULL);
        if (INVALID_HANDLE_VALUE == fileHandle) {
            ec = ECODE_FROM_WIN32(GetLastError());
            UnlockFile;
            return ec;
        }
        CloseHandle(fileHandle);
    }
    UnlockFile;

    LockFileList;
    pFile = LookUpFileObject(wcsName);
    if (NULL != pFile) {
        assert(!bExclusive);

        pFile->AddRef();
        *piBasicFile = pFile;
        UnlockFileList;
        return NOERROR;
    } else {
        pFile = new CBasicFile(static_cast<CBasicDirectory *>(this));
        if (NULL == pFile) {
            UnlockFileList;
            return E_OUT_OF_MEMORY;
        }

        if (bExclusive) {
           shareMode = FileShareMode_Deny;
        }

        ec = pFile->Initialize(wcsName, cmode, shareMode);
        if (FAILED(ec)) {
            UnlockFileList;
            return ec;
        }

        this->AddRef();
        pFile->AddRef();
        m_FileObjectList.InsertNext(pFile);
        *piBasicFile = pFile;
        UnlockFileList;
        return NOERROR;
    }

    assert(0);
}

ECode CBasicDirectory::DeleteFile(
    /* [in] */ WString name)
{
    WStringBuf_<_MAX_PATH> ws;
    wchar_t wcsName[_MAX_PATH] = {0,};
    ECode ec = NOERROR;
    Boolean bIsExist = false;
    Boolean bIsDir = false;
    BOOL ret = FALSE;
    Int32 fileAttribute =0;

    name = name.TrimEnd(ws);
    if (name.IsNullOrEmpty()
        || wcspbrk((const wchar_t *)name, wszIllegal) != NULL
        || name.GetLength() > (_MAX_PATH - 5) //MAX_PATH is 260
        || (name.GetLength() + wcslen(m_pDirName)) >= _MAX_PATH)
        return E_INVALID_ARGUMENT;

    MakeFullName(name, wcsName);

    LockFile;

    CheckFileType(wcsName, &bIsExist, &bIsDir);
    if (!bIsExist) {
        ec = E_FS_NO_SUCH_FILE;
        goto Exit;
    }
    if (bIsDir) {
        ec = E_FS_IS_DIRECTORY;
        goto Exit;
    }

    fileAttribute = GetFileAttributesW(wcsName);
    if (fileAttribute & FILE_ATTRIBUTE_READONLY) {
        ec = E_FS_NO_PERMISSION;
        goto Exit;
    }

    ret = ::DeleteFileW(wcsName);
    if (!ret)
        ec = E_FS_FILE_BUSY;

Exit:
    UnlockFile;
    return ec;
}

ECode CBasicDirectory::Rename(
    /* [in] */ WString oldName,
    /* [in] */ IBasicDirectory * pNewDir,
    /* [in] */ WString newName)
{
    Boolean bOldNameExist = FALSE;
    Boolean bOldNameIsDir = FALSE;
    Boolean bNewNameExist = FALSE;
    Boolean bNewNameIsDir = FALSE;
    BOOL bRet = FALSE;
    ECode ec = NOERROR;
    wchar_t oldNameArr[_MAX_PATH] = {0,};
    wchar_t newNameArr[_MAX_PATH] = {0,};

    if (oldName.IsNullOrEmpty()
        || newName.IsNullOrEmpty()
        || NULL == pNewDir
        || wcspbrk((const wchar_t *)newName, wszIllegal) != NULL
        || newName.GetLength() > (_MAX_PATH - 5) //MAX_PATH is 260
        || (newName.GetLength() + wcslen(m_pDirName)) >= _MAX_PATH) {
        return E_INVALID_ARGUMENT;
    }

    MakeFullName(oldName, oldNameArr);
    ((CBasicDirectory *)pNewDir)->MakeFullName(newName, newNameArr);

    if (0 == _wcsicmp(oldNameArr, newNameArr)) {
        return ec;
    }

    LockFile;
    CheckFileType(oldNameArr, &bOldNameExist, &bOldNameIsDir);
    CheckFileType(newNameArr, &bNewNameExist, &bNewNameIsDir);

    if (!bOldNameExist) {
        ec = E_FS_NO_SUCH_FILE;
        goto E_FAIL_EXIT;
    }

    if (bOldNameIsDir && bNewNameExist && !bNewNameIsDir) { // newname is file
        ec = E_FS_FILE_EXISTS;
        goto E_FAIL_EXIT;
    } else if (!bOldNameIsDir && bNewNameExist && bNewNameIsDir) {
        ec = E_FS_FILE_EXISTS;
        goto E_FAIL_EXIT;
    } else if (bNewNameExist) {
        ec = E_FS_FILE_EXISTS;
        goto E_FAIL_EXIT;
    }

    bRet = MoveFileW(oldNameArr, newNameArr);
    if (bRet) {
        UnlockFile;
        return ec;
    }

    ec = E_INVALID_ARGUMENT;

E_FAIL_EXIT:
    UnlockFile;
    return ec;
}

ECode CBasicDirectory::CreateDirectory(
    /* [in] */ WString name,
    /* [in] */ FileAccessMode mode)
{
    WStringBuf_<_MAX_PATH> ws;
    Boolean isExist = false;
    Boolean isDir = false;
    BOOL bSucceed = FALSE;
    wchar_t wcsName[_MAX_PATH] = {0,};
    ECode ec = NOERROR;

    name = name.TrimEnd(ws);

    if ((FileAccessMode_Read != mode 
        && FileAccessMode_Write != mode
        && FileAccessMode_ReadWrite != mode)
        || (name.IsNullOrEmpty()
        || name.GetLength() > (_MAX_PATH - 5)
        || NULL != wcspbrk((const wchar_t *)name, wszIllegal)
        || (name.GetLength() + wcslen(m_pDirName)) >= _MAX_PATH)) {
        return E_INVALID_ARGUMENT;
    }

    MakeFullName(name, wcsName);

    LockFile;

    CheckFileType(wcsName, &isExist, &isDir);
    if (isExist && isDir) {
        ec = E_FS_FILE_EXISTS;
        goto EXIT;
    }

    bSucceed = CreateDirectoryW(wcsName, NULL);
    if (FALSE == bSucceed) {
        ec = E_INVALID_OPERATION;
        goto EXIT;
    }

    if (FileAccessMode_Read == mode) {
        DWORD dirAttribute = GetFileAttributesW(wcsName);
        dirAttribute |= FILE_ATTRIBUTE_READONLY;
        SetFileAttributesW(wcsName, dirAttribute);
    }

EXIT:
    UnlockFile;
    return ec;
}

ECode CBasicDirectory::DeleteDirectory(
    /* [in] */ WString name)
{
    WStringBuf_<_MAX_PATH> ws;
    Boolean bIsExist = false;
    Boolean bIsDir = false;
    ECode ec = NOERROR;
    BOOL ret = FALSE;
    wchar_t wcsName[_MAX_PATH] = {0,};
    CBasicDirectory *pDir = NULL;

    name = name.TrimEnd(ws);
    if (name.IsNullOrEmpty()
        || wcspbrk((const wchar_t *)name, wszIllegal) != NULL) {
        return E_INVALID_ARGUMENT;
    }

    MakeFullName(name, wcsName);

    LockFile;
    CheckFileType(wcsName, &bIsExist, &bIsDir);
    if (!bIsExist) {
        ec = E_FS_NO_SUCH_FILE;
        goto EXIT;
    } else if (!bIsDir) {
        ec = E_FS_NOT_DIRECTORY;
        goto EXIT;
    }

    ret = RemoveDirectoryW(wcsName);
    if (!ret) {
        int errCode = GetLastError();
        if (ERROR_DIR_NOT_EMPTY == errCode)
            ec = E_FS_FILE_BUSY;
        else
            ec = E_INVALID_OPERATION;
    }

EXIT:
    UnlockFile;
    return ec;
}

ECode CBasicDirectory::GetDirEntries(
    /* [out] */ IWStringEnumerator ** ppiEnumerator)
{
    CDirEnumerator *pDirEnumerator = NULL;
    wchar_t path[_MAX_PATH] = {0,};

    if (NULL == ppiEnumerator) {
        E_INVALID_ARGUMENT;
    }

    wcscat(path, m_pDirName);
    wcscat(path, L"\\*.*");

    pDirEnumerator = new CDirEnumerator();
    if (NULL == pDirEnumerator) {
        return E_OUT_OF_MEMORY;
    }
    pDirEnumerator->Initialize(path);
    pDirEnumerator->AddRef();
    *ppiEnumerator = pDirEnumerator;

    return NOERROR;
}

ECode CBasicDirectory::AddFileMonitor(
    /* [out] */ IEvent **pEvent)
{
    FIXME;
    return E_NOT_IMPLEMENTED;
}

ECode CBasicDirectory::RemoveFileMonitor(
    /* [in] */ IEvent *pEvent)
{
    FIXME;
    return E_NOT_IMPLEMENTED;
}

inline ECode CBasicDirectory::CheckFileType(
    /* [in] */ wchar_t *wcsName, 
    /* [out] */ Boolean *isExist, 
    /* [out] */ Boolean *isDir)
{
    if (NULL == wcsName || NULL == isExist || NULL == isDir) {
        return E_INVALID_ARGUMENT;
    }

    Int32 fileAttr = GetFileAttributesW(wcsName);
    if (INVALID_FILE_ATTRIBUTES == fileAttr) {
        int ret = GetLastError();
        *isExist = false;
        return S_FALSE;
    }
    *isExist = true;
    *isDir = ((fileAttr & FILE_ATTRIBUTE_DIRECTORY) ? true:false);
    return NOERROR;
}

wchar_t *CBasicDirectory::GetDirName(void) const
{
    return m_pDirName;
}

inline CBasicDirectory* CBasicDirectory::LookUpDirObject(wchar_t *wcsName)
{
    CBasicDirectory *pDir = NULL;
    FOR_EACH_DLINKNODE(CBasicDirectory*, pDir, &m_DirObjectList) {
        if (!wcscpy(pDir->GetDirName(), wcsName)) {
            return pDir;
        }
    }
    return NULL;
}

inline CBasicFile *CBasicDirectory::LookUpFileObject(wchar_t *wcsName)
{
    CBasicFile *pFile = NULL;
    FOR_EACH_DLINKNODE(CBasicFile*, pFile, &m_FileObjectList) {
        if (!wcscpy(pFile->GetFileName(), wcsName)) {
            return pFile;
        }
    }
    return NULL;
}

Aura_Handle CBasicDirectory::GetDirObjectListLock()
{
    assert(NULL != m_hDirListLock);
    return m_hDirListLock;
}

Aura_Handle CBasicDirectory::GetFileObjectListLock()
{
    assert(NULL != m_hFileListLock);
    return m_hFileListLock;
}

ECode CBasicDirectory::GetDirTime()
{
    UInt64 tmp = 0;
    HANDLE hDir;
    WIN32_FIND_DATAW dirAttribute;

    hDir = FindFirstFileW(m_pDirName, &dirAttribute);
    if (INVALID_HANDLE_VALUE == hDir) {
        return ECODE_FROM_WIN32(GetLastError());
    }

    tmp = *(UInt64 *)&(dirAttribute.ftCreationTime);
    m_CreateTime = (UInt32)((tmp - bias64)/10000000);
    tmp = *(UInt64 *)&(dirAttribute.ftLastAccessTime);
    m_LastAccessTime = (UInt32)((tmp - bias64)/10000000);
    tmp = *(UInt64 *)&(dirAttribute.ftLastWriteTime);
    m_LastModifyTime = (UInt32)((tmp - bias64)/10000000);

    CloseHandle(hDir);
    return NOERROR;
}
